{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:18:39.889707Z",
     "start_time": "2025-01-24T03:18:37.456245Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:54:32.555477Z",
     "iopub.status.busy": "2025-01-25T07:54:32.555340Z",
     "iopub.status.idle": "2025-01-25T07:54:34.468991Z",
     "shell.execute_reply": "2025-01-25T07:54:34.468561Z",
     "shell.execute_reply.started": "2025-01-25T07:54:32.555454Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n",
    "np.random.seed(seed)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备数据\n",
    "\n",
    "这里使用subword分词，我们使用已经清洗好的数据集，可以从[此处](https://www.kaggleusercontent.com/kf/98352223/eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..nKt8lrIW5ej5QJQVpOWuqQ.oLIgiLMONU5Gpj_maVudRJa55NSOCILxk4JNZhvuXmeDBR-oG0uQm7bDHBfSwZRGvOBHQTsRV308iNP80btfwMinQ7yvJNt-GwdQF4XR4DIsg-2CbEPYiMsi_NdbL0FmE9LYStKdxCWbrCZCCMrTmo5LxR1txwibXaSpeP5Inobhbez5zetZIRH210CBuX2JbpRc_DULQpazKbtFPitwyfktVmdG_syvVAU6Sk9b0r0_erYAgb_jkKXX1Mxo1KzWSKLcAvbmMIPcsUkx9PmeJDs_wopfsQsZ1h5jaQX4_l0CTZrEenP6lIPDxpTwXANqqdHspmZeeEIAThqCHC6sb5DxTvG89BwzY9rc53Aa0uX4V806wJVybnRXoaV65K4GqpjnxbBK0WC8G-2lNtrqFujE89KDXZjFPgyfOEj1QIu13oFNSjgs6o4VV1PdZOrhiNdSmjb44c22l_unOaFojzJgzcPxq9AG2lcmrOpdZ2qu1jjdwey-58TA2ZHNCo3XnjEe2n3ignpnbsdLFpo22O8QakSUHv91wuYDYdNi3AiSmltL_k2ChuKfJ0G8kATpLe4k8wA26sO4GMXg4HImOr3b4aDVEIWXdApHP0ecFKs6ELTo8O7X-TK8Jvbua7e6qpDfDc-r_cD73fVSgSek5yNmKQMBzuVcjkprXmcxICQ.kV1b4N1s64NERKnt4zwQgQ/imdb_processed.csv)下载，分词使用 [subword-nmt](https://github.com/rsennrich/subword-nmt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:22:27.858055Z",
     "start_time": "2025-01-24T06:22:27.436613Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:54:34.470250Z",
     "iopub.status.busy": "2025-01-25T07:54:34.469957Z",
     "iopub.status.idle": "2025-01-25T07:54:34.798913Z",
     "shell.execute_reply": "2025-01-25T07:54:34.798465Z",
     "shell.execute_reply.started": "2025-01-25T07:54:34.470233Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(50000, 2)\n"
     ]
    }
   ],
   "source": [
    "cleaned_df = pd.read_csv(\"imdb_processed.csv\")\n",
    "print(cleaned_df.shape) # (50000, 2), 50000条评论, 2列\n",
    "\n",
    "# 随机打乱数据，取训练集和测试集\n",
    "np.random.seed(seed) #随机\n",
    "cleaned_df = cleaned_df.sample(frac=1).reset_index(drop=True)#打乱，frac=1表示全部打乱（frac是比例，reset_index(drop=True)是重新索引\n",
    "with open(\"imdb_train.txt\", \"w\", encoding=\"utf8\") as file:# 保存训练集\n",
    "    for line in cleaned_df.processed.values[:25000]:#只保存了processed列，即评论文本，没有保存label列\n",
    "        file.write(line.lower() + \"\\n\") #变为小写，token数量少一些\n",
    "\n",
    "with open(\"imdb_test.txt\", \"w\", encoding=\"utf8\") as file:# 保存测试集\n",
    "    for line in cleaned_df.processed.values[25000:]:\n",
    "        file.write(line.lower() + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T06:14:08.224959500Z",
     "start_time": "2024-05-02T06:14:08.190978500Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:54:34.799613Z",
     "iopub.status.busy": "2025-01-25T07:54:34.799437Z",
     "iopub.status.idle": "2025-01-25T07:54:38.851328Z",
     "shell.execute_reply": "2025-01-25T07:54:38.850770Z",
     "shell.execute_reply.started": "2025-01-25T07:54:34.799597Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.cloud.aliyuncs.com/pypi/simple\n",
      "Collecting subword-nmt\n",
      "  Downloading https://mirrors.cloud.aliyuncs.com/pypi/packages/1b/9a/488ecac22d78eb429928b9ee4f6b6c692e116ca4bd43ef42a475698def32/subword_nmt-0.3.8-py3-none-any.whl (27 kB)\n",
      "Collecting mock (from subword-nmt)\n",
      "  Downloading https://mirrors.cloud.aliyuncs.com/pypi/packages/6b/20/471f41173930550f279ccb65596a5ac19b9ac974a8d93679bcd3e0c31498/mock-5.1.0-py3-none-any.whl (30 kB)\n",
      "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/site-packages (from subword-nmt) (4.67.1)\n",
      "Installing collected packages: mock, subword-nmt\n",
      "Successfully installed mock-5.1.0 subword-nmt-0.3.8\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.3.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install subword-nmt  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:24:15.671594Z",
     "start_time": "2025-01-24T06:24:06.369793Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:54:38.852232Z",
     "iopub.status.busy": "2025-01-25T07:54:38.851997Z",
     "iopub.status.idle": "2025-01-25T07:54:54.518539Z",
     "shell.execute_reply": "2025-01-25T07:54:54.518008Z",
     "shell.execute_reply.started": "2025-01-25T07:54:38.852212Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100%|#####################################| 8000/8000 [00:07<00:00, 1049.57it/s]\n"
     ]
    }
   ],
   "source": [
    "# 学习bpe分词(很慢,学一次就好)\n",
    "# -i 选择学习的文件\n",
    "# -o 核心输出文件,分词需要用到imdb_bpe_code\n",
    "# --write-vocabulary 字典输出文件\n",
    "# -s 词表大小\n",
    "!subword-nmt learn-joint-bpe-and-vocab -i ./imdb_train.txt -o ./imdb_bpe_code --write-vocabulary ./imdb_bpe_vocab -s 8000\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:27:23.512416Z",
     "start_time": "2025-01-24T06:27:17.835322Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-25T07:54:54.519427Z",
     "iopub.status.busy": "2025-01-25T07:54:54.519192Z",
     "iopub.status.idle": "2025-01-25T07:55:05.132190Z",
     "shell.execute_reply": "2025-01-25T07:55:05.131605Z",
     "shell.execute_reply.started": "2025-01-25T07:54:54.519409Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# 应用bpe分词,-c 指定 BPE 编码的配置文件\n",
    "!subword-nmt apply-bpe -c ./imdb_bpe_code -i ./imdb_train.txt -o ./imdb_train_bpe.txt\n",
    "!subword-nmt apply-bpe -c ./imdb_bpe_code -i ./imdb_test.txt -o ./imdb_test_bpe.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:27:28.092595Z",
     "start_time": "2025-01-24T06:27:27.981169Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:05.133101Z",
     "iopub.status.busy": "2025-01-25T07:55:05.132872Z",
     "iopub.status.idle": "2025-01-25T07:55:05.248937Z",
     "shell.execute_reply": "2025-01-25T07:55:05.248447Z",
     "shell.execute_reply.started": "2025-01-25T07:55:05.133082Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ tain look overall interesting reason . anyways , could one best sum@@ mer@@ sla@@ m ever w@@ w@@ f le@@ x lu@@ ger main event yo@@ ko@@ z@@ un@@ a , time ok huge fat man v strong man i glad time changed . it terrible main event like every match lu@@ ger terrible . other match card ra@@ z@@ or ra@@ mon v ted di@@ bi@@ ase , ste@@ in@@ er brothers v hea@@ ven@@ ly bo@@ dies , sha@@ wn micha@@ els v cur@@ t h@@ ening , event sha@@ wn named big monster body guard die@@ sel , irs v - - kid , bre@@ t hart first take do@@ ink take jerry law@@ ler stuff har@@ ts law@@ ler always interesting , lu@@ d@@ vi@@ g bor@@ ga destroyed marty jan@@ ne@@ tty , under@@ taker took giant gon@@ z@@ ale@@ z another terrible match , the smoking g@@ unn@@ s tat@@ an@@ ka took ba@@ m ba@@ m bi@@ ge@@ low head@@ shr@@ in@@ kers , yo@@ ko@@ z@@ un@@ a def@@ ended world title le@@ x lu@@ ger match boring terrible ending . however deserves\n",
      "not many television show appeal quite many different kind fan like far@@ scape . . . i know youn@@ g@@ ster year old fan male female many different country think ad@@ ore t . v miniseries . it element found almost every show t . v , character driven drama could australian soap opera yet episode science fact fiction would give even har@@ di@@ est tre@@ k@@ kie run money brain@@ ben@@ der sta@@ ke ! wor@@ m@@ hole theory , time travel true equ@@ a@@ tional form . . . magnificent . it embr@@ ace culture ma@@ p possibility endless multiple star therefore thousand planet choose . with broad scope would expected nothing would able keep illu@@ sion long , far@@ scape really come element . . . it succeeds others failed , especially like star trek universe practically zero ka@@ os element ! they ran idea pretty quickly kept re@@ ha@@ shing ! over course season manage keep audience attention using good continuity constant character evol@@ ution multiple thread every episode unique personal touch camera specific certain character group within whole . this structure allows extremely large area subject matter loy@@ alty for@@ ged broken many way many many issue . i happened see pilot premiere passing keep tun@@ ing see cri@@ ch@@ ton would ever get girl , seeing television i deli@@ ghted see available dvd i admit thing kept s@@ ane whilst i hour night shift developed chron@@ ic in@@ som@@ nia . . . far@@ scape thing get extremely long night . . . do fav@@ our watch pilot see i mean . . . far@@ scape com@@ et\n",
      "the film quickly get major chase scene ever increa@@ sing destruction . the first really bad thing guy hi@@ jac@@ king steven seagal would beaten pulp seagal driving , probably would ended whole premise movie . it seems like decided make kind change movie plot , plan enjoy action , expect coherent plot . turn sense logic may , re@@ duce chance getting head@@ ache . i give hope steven seagal trying move back towards type character portrayed popular movie .\n",
      "jane austen would definitely appro@@ ve one ! g@@ wy@@ ne@@ th pal@@ tro@@ w awesome job capturing attitude emma . she funny without exce@@ ssively silly , yet eleg@@ ant . she put convincing british accent british , maybe i best judge , fooled . . . also excellent sli@@ ding do@@ ors . . . i sometimes forget american ! . also brilliant jeremy north@@ am sophi@@ e th@@ omp@@ son ph@@ y@@ lli@@ da law emma th@@ omp@@ son sister mother bates woman . they nearly steal show . . . ms . law even line ! highly recommended .\n",
      "expec@@ ta@@ tions somewhat high i went see movie , i thought steve care@@ ll could wrong coming great movie like an@@ chor@@ man , the year - old virgin , little miss sun@@ shine . boy , i wrong . i start right movie certain point steve care@@ ll allowed steve care@@ ll . there handful moment film made laugh , due almost entirely given wi@@ ggle - room thing . he undoubtedly talented individual , shame sig@@ ned turned , opinion , total train - wreck . with way , i discus went horri@@ f@@ y@@ ingly wrong . the film begin dan burns , wi@@ do@@ wer three girl considered na@@ tionally syn@@ di@@ cated advice colum@@ n . he pre@@ pa@@ res girl family reunion , extended relative ga@@ ther time . the family high at@@ op list thing make awful movie . no family beha@@ ves like . it almost tran@@ spor@@ ted pleasan@@ t@@ ville leave bea@@ ver . they caricature think family . it reach point become obnoxious simply frustrating . touch football , cro@@ ss@@ word puzzle competition , family bow@@ ling , talent show are not how actual people behave . it almost sick@@ ening . another big flaw woman care@@ ll supposed falling . obser@@ ving first scene steve care@@ ll like watching stro@@ ke victim trying re@@ hab@@ il@@ it@@ ated . what i imagine supposed unique original woman come mildly retarded . it make think movie taking place another planet . i left theater wondering i saw . after thinking , i think much .\n",
      "i watched movie fairly regular basis life , never get old . for sni@@ de remark insult mostly david spa@@ de , tommy boy giant heart . and keep movie funny year . tommy cal@@ la@@ han chris far@@ ley son big tom cal@@ la@@ han brian den@@ ne@@ h@@ y , master car part sal@@ es@@ man , ri@@ dden life . but died dy wedding day , tommy learns company deb@@ t , bought ray z@@ al@@ in@@ sky dan ak@@ roy@@ d , owner huge car part company . so order save company , tommy go road sell company new bra@@ ke pa@@ d . along ride , though choice , richard hay@@ den david spa@@ de former cla@@ ss@@ mate tommy big tom right - hand man . the movie ride chemistry two sn@@ l star real - life best friend chris far@@ ley david spa@@ de . the duo enough comic energy going power world . it big , dumb guy versus smart little guy . it work , scene un@@ forget@@ tably funny . far@@ ley spa@@ de actually decent dramatic actor well . although film primarily comedy , fair share drama , spa@@ de especially far@@ ley good making audience laugh . forgive , i talk chris far@@ ley little . i read biography the chris far@@ ley show a biography three acts , anyone care , understanding chris real life made movie special . chris far@@ ley genuinely good person strugg@@ led , ultimately failed con@@ qu@@ er addic@@ tion . although first movie major role , best film . it really showed , much talent . knowing chris story add another layer movie , although make le funny . far@@ ley spa@@ de matched good screen cast . rob lo@@ we suit@@ ably sli@@ my tommy new brother , bo derek solid step - mother . brian den@@ ne@@ h@@ y great big tom . den@@ ne@@ h@@ y make easy believe father son . big tom crazy son , although smar@@ ter mature . dan ak@@ roy@@ d give one best performance z@@ al@@ in@@ sky , giving tommy hard truth behind advertising . julie warner also good tommy love interest , michelle . for , peter se@@ gal one great comedy director . he keep pace quick ener@@ ge@@ tic , importantly , know make comedy funny . he be@@ la@@ bor joke , understand@@ s funny actor know allows . but se@@ gal go step . he give tommy boy friendly , almost nostal@@ gic tone tu@@ g heart@@ str@@ ings genuinely ti@@ ckle f@@ unn@@ y@@ bone . cri@@ tics like tommy boy . shame . a movie super sophisticated sub@@ ver@@ sively intellectual funny god for@@ bid far@@ ley spa@@ de forced mu@@ ted comedy la the office . this great movie one - time favorite .\n",
      "for story hope high@@ ligh@@ ted tragic reality youth face . fav@@ ela rising draw one scary , un@@ safe un@@ fair world show beautiful color moving music one man dedicated friend choose accept world change action art . an entertaining , interesting , emotional , aes@@ the@@ tically beautiful film . i showed film numerous high school student well live neighborhood poverty gun violence en@@ amo@@ red anderson , protagonist . i recommend film age due subtitle image death background .\n",
      "okay , i get pur@@ gatory thing first time i watched episode . it seemed like something significant going i put finger . this time co@@ sta me@@ sa fire tv really caught attention - helped i writing ess@@ ay inf@@ er@@ no ! but let see ha@@ s@@ n t discu@@ ssed yet . . . a tw@@ op review mentioned tony flight sta@@ ir go broken elev@@ ator . yeah , significant number lot reason , especially religious , one ya . on hun@@ ch i con@@ sulted wi@@ ki@@ pe@@ dia , guess dan@@ te divi@@ ded level ? pur@@ g@@ at@@ ori@@ o . exclu@@ ding ante - pur@@ gatory para@@ di@@ se . the stuff bottom sta@@ ir . . . tony get . on alle@@ ge@@ dly random mon@@ k - slap scene . as soon mon@@ k appeared , fit perfectly place tony trying get pur@@ gatory . you tell got worried christian commercial death , disease , sin came , getting desperate christian heaven looking kinda i@@ ffy . by time meet mon@@ k thinking hey maybe guy help ? sound like contem@@ pla@@ ting religion e . g . bud@@ d@@ h@@ ism wondering path could take sal@@ vation . not tony necessarily literally thinking becoming bud@@ d@@ hi@@ st , appears fin@@ ner@@ ty tried me@@ ssed . that slap face basically tell tony quick fix - , , suddenly embr@@ ace bud@@ d@@ h@@ ism get . tony initially concerned getting heaven . but con@@ ference en@@ tr@@ ance , realizes going easy . at first i saw name v . driver li@@ cen@@ se problem tony led sort double life , killing people sleeping around kept secret people . he feel free affair qu@@ as@@ i - mel@@ fi kevin fin@@ ner@@ ty . he figure can fool people k@@ f card , like hotel rec@@ ep@@ tion@@ ist , get pur@@ gatory . those helicopter - helicopter heaven ? - keeping track everything . after reading theory in@@ fin@@ ner@@ ty , though , seems like k@@ f identity remin@@ der in@@ fin@@ ite different path tony could taken life . possibly along car joke involving in@@ fin@@ it@@ i made sense otherwise . a@@ a@@ and point brain fi@@ zz@@ le .\n",
      "i disappointed series . it lot cool graphic . the level detail went minimal , i always got feeling audience pat@@ ron@@ ized - - lot seemed this extremely cool going explain detail get anyway . let show pretty picture entertain . the host would drop interesting - sounding word spar@@ tic@@ les super - sym@@ me@@ try without attempt explaining . we look wi@@ ki@@ pe@@ dia . furthermore , i know quite bit super@@ string la@@ y@@ man i found explanation convoluted could much better . they could chosen much better example explain concept , instead , example used confusing ob@@ scu@@ red subject . ad@@ di@@ tionally , i got sick repeti@@ ti@@ veness . they could easily con@@ den@@ sed series one episode cut repeti@@ tion . they must shown clip qu@@ an@@ tum ca@@ f time . the host kept saying thing . i remember many time said the universe made tiny little vi@@ bra@@ ting string . it like trying brain@@ wa@@ sh u accep@@ ting super@@ string best thing since sli@@ ced b@@ read . finally , show ended unpleasant sense competition fer@@ mil@@ a@@ b cer@@ n , clearly bi@@ ased towards fer@@ mil@@ a@@ b . this supposed edu@@ cational program qu@@ an@@ tum physi@@ c , whether us better europe vice ver@@ sa ! i also felt part pat@@ ron@@ i@@ zing - - audi@@ en@@ ces need see conflict remain interested . please . give little credit . overall , thumb -\n",
      "the first minute tin@@ sel@@ town finger te@@ e@@ tering remote , po@@ ised flick around watch something else . the premise two writer , luck , living self - stor@@ age - space bin mildly amusing , , painfully bland . the introduction character , played joe pan@@ to@@ li@@ ano - big deal movie guy , life park sleep la@@ v@@ atory , offered hope i decided give minute . and kri@@ sty s@@ wan@@ sons introduction bud@@ ding film director bor@@ der@@ line ny@@ mp@@ hom@@ ani@@ ac , added bit sp@@ ice . her solid acting performance raised presence beyond welcome eye - candy inclu@@ sion . ultimately , obvious low - budget impact film poorly shot scene , stu@@ t@@ tured pace slapstick hand@@ ling certain moment . some favourite movie time low budget , whi@@ th@@ nail i one also deal guy dream , luck . however , money , actor save tin@@ sel@@ town terrible movie archi@@ ve nu@@ dge could cult movie archi@@ ve . i laughed loud scene involving joe pan@@ to@@ li@@ ano character . in particular , pen@@ ultimate scene terribly clichd , still funny , rich - - scre@@ wed - character house , story un@@ ra@@ vel@@ s towards final moment . i see tin@@ sel@@ town great stage play film - maker best transla@@ te celluloid , simply work i laughed loud scene one liner , i think first minute du@@ lled sen@@ s expectation degree i would laughed anything . unless stuck no@@ vel@@ ty coffee coa@@ ster , pick see bar@@ gain bu@@ cket .\n"
     ]
    }
   ],
   "source": [
    "# 分词后的数据长什么样,与分词前imdb_train.txt进行对比来理解，@@ 是分词的标记，如果一个单词被分开，就会加上@@\n",
    "!head ./imdb_train_bpe.txt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:32:25.720382Z",
     "start_time": "2025-01-24T06:32:25.705278Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:05.251832Z",
     "iopub.status.busy": "2025-01-25T07:55:05.251507Z",
     "iopub.status.idle": "2025-01-25T07:55:05.261381Z",
     "shell.execute_reply": "2025-01-25T07:55:05.260967Z",
     "shell.execute_reply.started": "2025-01-25T07:55:05.251813Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>processed</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>I really liked Summerslam due look arena , cur...</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Not many television show appeal quite many dif...</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>The film quickly get major chase scene ever in...</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Jane Austen would definitely approve one ! Gwy...</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Expectations somewhat high I went see movie , ...</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                           processed  label\n",
       "0  I really liked Summerslam due look arena , cur...      1\n",
       "1  Not many television show appeal quite many dif...      1\n",
       "2  The film quickly get major chase scene ever in...      0\n",
       "3  Jane Austen would definitely approve one ! Gwy...      1\n",
       "4  Expectations somewhat high I went see movie , ...      0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cleaned_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:33:21.681977Z",
     "start_time": "2025-01-24T06:33:20.743071Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:05.262349Z",
     "iopub.status.busy": "2025-01-25T07:55:05.261938Z",
     "iopub.status.idle": "2025-01-25T07:55:06.597732Z",
     "shell.execute_reply": "2025-01-25T07:55:06.597262Z",
     "shell.execute_reply.started": "2025-01-25T07:55:05.262321Z"
    }
   },
   "outputs": [],
   "source": [
    "subwords = []\n",
    "with open(\"imdb_train_bpe.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in file.readlines():\n",
    "        subwords.append(line.strip())\n",
    "        \n",
    "with open(\"imdb_test_bpe.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in file.readlines():\n",
    "        subwords.append(line.strip())\n",
    "        \n",
    "cleaned_df[\"subwords10k\"] = subwords # 保存分词后的结果\n",
    "cleaned_df[\"split\"] = [\"train\"] * 25000 + [\"test\"] * 25000 # 标记训练集和测试集\n",
    "cleaned_df.to_csv(\"imdb_subwords.csv\", index=False) #把分词后的结果保存到csv文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:35:50.272092Z",
     "start_time": "2025-01-24T06:35:49.368592Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:06.598857Z",
     "iopub.status.busy": "2025-01-25T07:55:06.598372Z",
     "iopub.status.idle": "2025-01-25T07:55:07.717960Z",
     "shell.execute_reply": "2025-01-25T07:55:07.717439Z",
     "shell.execute_reply.started": "2025-01-25T07:55:06.598826Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "# 随后加载数据集就从bpe分词的文件里加载\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, mode=\"train\"):\n",
    "        df = pd.read_csv(\"imdb_subwords.csv\").query(\"split == '{}'\".format(mode)) # 加载训练集或测试集，query语句筛选\n",
    "        self.texts = df[\"subwords10k\"].values # 评论文本\n",
    "        self.labels = df[\"label\"].values # 评论标签\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.labels)\n",
    "    \n",
    "    def __getitem__(self, idx):\n",
    "        return self.texts[idx].split(), self.labels[idx] # 返回文本和标签\n",
    "    \n",
    "    \n",
    "train_ds = IMDBDataset(\"train\")\n",
    "test_ds = IMDBDataset(\"test\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:35:55.250388Z",
     "start_time": "2025-01-24T06:35:55.246372Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:07.719099Z",
     "iopub.status.busy": "2025-01-25T07:55:07.718644Z",
     "iopub.status.idle": "2025-01-25T07:55:07.725194Z",
     "shell.execute_reply": "2025-01-25T07:55:07.724748Z",
     "shell.execute_reply.started": "2025-01-25T07:55:07.719072Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(['i',\n",
       "  'really',\n",
       "  'liked',\n",
       "  'sum@@',\n",
       "  'mer@@',\n",
       "  'sla@@',\n",
       "  'm',\n",
       "  'due',\n",
       "  'look',\n",
       "  'a@@',\n",
       "  'ren@@',\n",
       "  'a',\n",
       "  ',',\n",
       "  'cur@@',\n",
       "  'tain',\n",
       "  'look',\n",
       "  'overall',\n",
       "  'interesting',\n",
       "  'reason',\n",
       "  '.',\n",
       "  'anyways',\n",
       "  ',',\n",
       "  'could',\n",
       "  'one',\n",
       "  'best',\n",
       "  'sum@@',\n",
       "  'mer@@',\n",
       "  'sla@@',\n",
       "  'm',\n",
       "  'ever',\n",
       "  'w@@',\n",
       "  'w@@',\n",
       "  'f',\n",
       "  'le@@',\n",
       "  'x',\n",
       "  'lu@@',\n",
       "  'ger',\n",
       "  'main',\n",
       "  'event',\n",
       "  'yo@@',\n",
       "  'ko@@',\n",
       "  'z@@',\n",
       "  'un@@',\n",
       "  'a',\n",
       "  ',',\n",
       "  'time',\n",
       "  'ok',\n",
       "  'huge',\n",
       "  'fat',\n",
       "  'man',\n",
       "  'v',\n",
       "  'strong',\n",
       "  'man',\n",
       "  'i',\n",
       "  'glad',\n",
       "  'time',\n",
       "  'changed',\n",
       "  '.',\n",
       "  'it',\n",
       "  'terrible',\n",
       "  'main',\n",
       "  'event',\n",
       "  'like',\n",
       "  'every',\n",
       "  'match',\n",
       "  'lu@@',\n",
       "  'ger',\n",
       "  'terrible',\n",
       "  '.',\n",
       "  'other',\n",
       "  'match',\n",
       "  'card',\n",
       "  'ra@@',\n",
       "  'z@@',\n",
       "  'or',\n",
       "  'ra@@',\n",
       "  'mon',\n",
       "  'v',\n",
       "  'ted',\n",
       "  'di@@',\n",
       "  'bi@@',\n",
       "  'ase',\n",
       "  ',',\n",
       "  'ste@@',\n",
       "  'in@@',\n",
       "  'er',\n",
       "  'brothers',\n",
       "  'v',\n",
       "  'hea@@',\n",
       "  'ven@@',\n",
       "  'ly',\n",
       "  'bo@@',\n",
       "  'dies',\n",
       "  ',',\n",
       "  'sha@@',\n",
       "  'wn',\n",
       "  'micha@@',\n",
       "  'els',\n",
       "  'v',\n",
       "  'cur@@',\n",
       "  't',\n",
       "  'h@@',\n",
       "  'ening',\n",
       "  ',',\n",
       "  'event',\n",
       "  'sha@@',\n",
       "  'wn',\n",
       "  'named',\n",
       "  'big',\n",
       "  'monster',\n",
       "  'body',\n",
       "  'guard',\n",
       "  'die@@',\n",
       "  'sel',\n",
       "  ',',\n",
       "  'irs',\n",
       "  'v',\n",
       "  '-',\n",
       "  '-',\n",
       "  'kid',\n",
       "  ',',\n",
       "  'bre@@',\n",
       "  't',\n",
       "  'hart',\n",
       "  'first',\n",
       "  'take',\n",
       "  'do@@',\n",
       "  'ink',\n",
       "  'take',\n",
       "  'jerry',\n",
       "  'law@@',\n",
       "  'ler',\n",
       "  'stuff',\n",
       "  'har@@',\n",
       "  'ts',\n",
       "  'law@@',\n",
       "  'ler',\n",
       "  'always',\n",
       "  'interesting',\n",
       "  ',',\n",
       "  'lu@@',\n",
       "  'd@@',\n",
       "  'vi@@',\n",
       "  'g',\n",
       "  'bor@@',\n",
       "  'ga',\n",
       "  'destroyed',\n",
       "  'marty',\n",
       "  'jan@@',\n",
       "  'ne@@',\n",
       "  'tty',\n",
       "  ',',\n",
       "  'under@@',\n",
       "  'taker',\n",
       "  'took',\n",
       "  'giant',\n",
       "  'gon@@',\n",
       "  'z@@',\n",
       "  'ale@@',\n",
       "  'z',\n",
       "  'another',\n",
       "  'terrible',\n",
       "  'match',\n",
       "  ',',\n",
       "  'the',\n",
       "  'smoking',\n",
       "  'g@@',\n",
       "  'unn@@',\n",
       "  's',\n",
       "  'tat@@',\n",
       "  'an@@',\n",
       "  'ka',\n",
       "  'took',\n",
       "  'ba@@',\n",
       "  'm',\n",
       "  'ba@@',\n",
       "  'm',\n",
       "  'bi@@',\n",
       "  'ge@@',\n",
       "  'low',\n",
       "  'head@@',\n",
       "  'shr@@',\n",
       "  'in@@',\n",
       "  'kers',\n",
       "  ',',\n",
       "  'yo@@',\n",
       "  'ko@@',\n",
       "  'z@@',\n",
       "  'un@@',\n",
       "  'a',\n",
       "  'def@@',\n",
       "  'ended',\n",
       "  'world',\n",
       "  'title',\n",
       "  'le@@',\n",
       "  'x',\n",
       "  'lu@@',\n",
       "  'ger',\n",
       "  'match',\n",
       "  'boring',\n",
       "  'terrible',\n",
       "  'ending',\n",
       "  '.',\n",
       "  'however',\n",
       "  'deserves'],\n",
       " 1)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ds[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 word2idx 和 idx2word"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:36:22.298401Z",
     "start_time": "2025-01-24T06:36:22.295299Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:07.726207Z",
     "iopub.status.busy": "2025-01-25T07:55:07.725813Z",
     "iopub.status.idle": "2025-01-25T07:55:07.729805Z",
     "shell.execute_reply": "2025-01-25T07:55:07.729309Z",
     "shell.execute_reply.started": "2025-01-25T07:55:07.726179Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0: '[PAD]', 1: '[BOS]', 2: '[UNK]', 3: '[EOS]'}\n"
     ]
    }
   ],
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典\n",
    "word2idx = {\n",
    "    \"[PAD]\": 0,     # 填充 token\n",
    "    \"[BOS]\": 1,     # begin of sentence\n",
    "    \"[UNK]\": 2,     # 未知 token\n",
    "    \"[EOS]\": 3,     # end of sentence\n",
    "}\n",
    "idx2word = {value: key for key, value in word2idx.items()}\n",
    "print(idx2word)\n",
    "index = len(idx2word) # 词表长度，现在为4\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:39:49.547123Z",
     "start_time": "2025-01-24T06:39:49.532122Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:07.730874Z",
     "iopub.status.busy": "2025-01-25T07:55:07.730464Z",
     "iopub.status.idle": "2025-01-25T07:55:07.744097Z",
     "shell.execute_reply": "2025-01-25T07:55:07.743629Z",
     "shell.execute_reply.started": "2025-01-25T07:55:07.730847Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 8031/8031 [00:00<00:00, 1313080.55it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vocab_size: 8035\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "threshold = 1  # 出现次数低于此的token舍弃\n",
    "with open(\"imdb_bpe_vocab\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in tqdm(file.readlines()):\n",
    "        token, counts = line.strip().split()\n",
    "        if int(counts) >= threshold:\n",
    "            word2idx[token] = index # 加入词表\n",
    "            idx2word[index] = token # 加入反向词典\n",
    "            index += 1\n",
    "\n",
    "vocab_size = len(word2idx)\n",
    "print(\"vocab_size: {}\".format(vocab_size))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:40:24.355459Z",
     "start_time": "2025-01-24T06:40:23.470404Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:07.744888Z",
     "iopub.status.busy": "2025-01-25T07:55:07.744633Z",
     "iopub.status.idle": "2025-01-25T07:55:08.785779Z",
     "shell.execute_reply": "2025-01-25T07:55:08.785059Z",
     "shell.execute_reply.started": "2025-01-25T07:55:07.744874Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAANshJREFUeJzt3Xl8VNX9//H3bAmJZjFAtkoIArIoi0YNcUFaUgPigqAVpQhKwQWsSqWIvypov98vVC3UWkRbFagiuFShxe3BjksAoaDggkCjYEkChSYBkWSW8/uj39yvIwmTwIS5yX09H495cObeM3c+h5vcfOacc8+4jDFGAAAANuKOdQAAAADfR4ICAABshwQFAADYDgkKAACwHRIUAABgOyQoAADAdkhQAACA7ZCgAAAA2/HGOoDjEQqFtGfPHiUlJcnlcsU6HAAA0ADGGB08eFDZ2dlyu4/dR9IsE5Q9e/aoXbt2sQ4DAAAch927d+v0008/Zp1mmaAkJSVJ+k8Dk5OTYxwNAABoiKqqKrVr1876O34szTJBqR3WSU5OJkFBowSDQa1du1aS1KdPH3k8nhhHBADO05DpGc0yQQGOVzAY1LJlyyRJ559/PgkKANgUCQocxe12q1evXlYZAGBPJChwFK/Xq8GDB8c6DABABCQoAICoM8YoEAgoGAzGOhScRB6PR16vNypLgJCgAACiqqamRqWlpTp8+HCsQ0EMJCYmKisrS3FxcSd0HBIUOEpNTY1mzJghSZowYcIJ/wIBCBcKhVRSUiKPx6Ps7GzFxcWxoKZDGGNUU1Ojffv2qaSkRJ07dz6huX4kKHCc6urqWIcAtFg1NTUKhUJq166dEhMTYx0OTrKEhAT5fD599dVXqqmpUatWrY77WCQocBSfz6fx48dbZQBNg7vknCta554EBY7icrnUunXrWIcBAIiAFBcAAJtxuVxatGhRrMOQJE2dOlW9e/c+6e9LggJHCQaDWr9+vdavX8/tjwDwPXZKjBjigaMEg0G99dZbkqTevXuz1D0A2BQ9KHAUt9ut7t27q3v37kziAxCmX79+uvPOO3X33XfrtNNOU0ZGhv70pz/pm2++0c0336ykpCR16tTJ+pAj/edDz+jRo9WhQwclJCSoS5cuevzxx639R44c0VlnnaWxY8da23bu3KmkpCQ999xzDY5t9+7d+slPfqLU1FSlpaXp6quv1pdffmntHzVqlAYPHqzHHntMWVlZat26tcaNGye/32/VKS0t1aBBg5SQkKAOHTroxRdfVG5urn73u99JknJzcyVJ11xzjVwul/W81vPPP6/c3FylpKRo2LBhOnjwYIPjPx5coeEoXq9X1113na677jp5vXQgAidTTU2NampqZIyxtgWDQdXU1CgQCES17vGaN2+e2rRpo/Xr1+vOO+/U7bffruuuu04XXnih/v73v+uyyy7TiBEjrEXoQqGQTj/9dL3yyiv69NNP9eCDD+r+++/Xyy+/LElq1aqV5s+fr3nz5mnx4sUKBoP66U9/qh//+Me65ZZbGhST3+9XUVGRkpKS9O677+r999/XqaeeqgEDBqimpsaqt3LlSu3cuVMrV67UvHnzNHfuXM2dO9faf9NNN2nPnj1atWqV/vKXv+iPf/yj9u7da+3/8MMPJUlz5sxRaWmp9Vz6T1K1aNEiLVmyREuWLNHq1as1ffr04/5/bhDTDFVWVhpJprKyMtahAAC+49tvvzWffvqp+fbbb4/aN3XqVDN16lRz6NAha9vq1avN1KlTzeLFi8Pq/vd//7eZOnWq+fe//21tKy4uNlOnTjV/+ctfwuo+8sgjZurUqaa8vPyEYr/00kvNxRdfbD0PBALmlFNOMSNGjLC2lZaWGkmmuLi43uOMGzfODB069KgY27RpY8aPH2+ysrLMv/71r2PGIsm8/vrrxhhjnn/+edOlSxcTCoWs/dXV1SYhIcG88847xhhjRo4cadq3b28CgYBV57rrrjPXX3+9McaYzz77zEgyH374obV/+/btRpKZOXNmne9ba8qUKSYxMdFUVVVZ2yZOnGjy8/PrjP1YPwON+fvNR0gAAP5Xz549rbLH41Hr1q3Vo0cPa1tGRoYkhfU8zJo1S88995x27dqlb7/9VjU1NUfd9fKLX/xCixYt0h/+8Ae99dZbjVru4KOPPtKOHTuUlJQUtv3IkSPauXOn9fyss84Km1eXlZWlLVu2SJK2bdsmr9erc88919rfqVMnnXbaaQ2KITc3N+z9s7Kywv4PmgIJChzF7/friSeekCTdeeedLNYGnESTJ0+WFL5I4kUXXaQ+ffocNSfs3nvvParu+eefr3PPPfeounfddddRdY/X94/hcrnCttUu2x8KhSRJCxcu1L333qvf/va3KigoUFJSkh59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kszrr78etn/69OkmJSXFLFq0yHz00UfmqquuMh06dDDffvutVWfAgAGmV69eZu3atebdd981nTp1MjfccIO1v7Ky0mRkZJjhw4ebrVu3mgULFpiEhATz9NNPn6xmHuVY7a6oqDCFhYXmpZdeMp9//rkpLi42F1xwgcnLyws7Rvv27c3DDz8c9jPw3WuB3dod6VyPHDnSDBgwIKw9Bw4cCKvT0s61MSasvaWlpea5554zLpfL7Ny506rT3M51JCQoxpgLLrjAjBs3znoeDAZNdna2mTZtWgyjip69e/caSWb16tXWtksvvdTcdddd9b7mzTffNG6325SVlVnbZs+ebZKTk011dXVThntcpkyZYnr16lXnvoqKCuPz+cwrr7xibfvss8+MJFNcXGyMaX7trc9dd91lOnbsaEKhkDGm5Z1nY8xRF+9QKGQyMzPNo48+am2rqKgw8fHxZsGCBcYYYz799FMjyXz44YdWnbfeesu4XC7zz3/+0xhjzJNPPmlOO+20sHZPmjTJdOnSpYlb1DB1/dH6vvXr1xtJ5quvvrK2tW/f3sycObPe19i53fUlKFdffXW9r3HKub766qvNj370o7Btzflc18XxQzw1NTXauHGjCgsLrW1ut1uFhYUqLi6OYWTRU1lZKUlKS0sL2z5//ny1adNGZ599tiZPnqzDhw9b+4qLi9WjR4+whfOKiopUVVWlTz755OQE3kjbt29Xdna2zjjjDA0fPly7du2SJG3cuFF+vz/sHHft2lU5OTnWOW6O7f2+mpoavfDCC7rlllvCvkSzpZ3n7yspKVFZWVnY+U1JSVF+fn7Y+U1NTdV5551n1SksLJTb7da6deusOn379lVcXJxVp6ioSNu2bdO///3vk9SaE1NZWSmXy3XUd5VNnz5drVu31jnnnKNHH300bAivObZ71apVSk9PV5cuXXT77bdr//791j4nnOvy8nK98cYbGj169FH7WtK5bhbfZtyU/vWvfykYDB61gm1GRoY+//zzGEUVPaFQSHfffbcuuuginX322db2G2+8Ue3bt1d2drY+/vhjTZo0Sdu2bdNrr70mSSorK6vz/6R2n93k5+dr7ty56tKli0pLS/XQQw/pkksu0datW1VWVqa4uLijLtoZGRlWW5pbe+uyaNEiVVRUaNSoUda2lnae61IbZ13t+O75TU9PD9vv9XqV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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 选择 max_length\n",
    "length_collect = {}\n",
    "for text, label in train_ds:\n",
    "    length = len(text)\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1\n",
    "    \n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tokenizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:44:33.165369Z",
     "start_time": "2025-01-24T06:44:33.158363Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.786619Z",
     "iopub.status.busy": "2025-01-25T07:55:08.786398Z",
     "iopub.status.idle": "2025-01-25T07:55:08.795298Z",
     "shell.execute_reply": "2025-01-25T07:55:08.794918Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.786603Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text-------------------\n",
      "['hello', 'world']\n",
      "['i', 'really', 'liked', 'sum@@', 'mer@@', 'sla@@', 'm', 'due', 'look', 'a@@', 'ren@@', 'a', ',', 'cur@@']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices---------------\n",
      "tensor([   1, 6513,  125,    3,    0,    0,    0,    0,    0,    0,    0,    0,\n",
      "           0,    0,    0,    0])\n",
      "tensor([   1,    6,   27,  514, 2230,  775, 1527,  146,  893,   65,   98,  666,\n",
      "          26,    5, 1571,    3])\n",
      "tensor([   1,   18,  395,   26, 1892,    3,    0,    0,    0,    0,    0,    0,\n",
      "           0,    0,    0,    0])\n"
     ]
    }
   ],
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "    \n",
    "    def encode(self, text_list, padding_first=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.bos_idx] + [self.word2idx.get(word, self.unk_idx) for word in text[:max_length-2]] + [self.eos_idx] #变为id，未登录词用unk_idx代替，句子前后加bos和eos\n",
    "            if padding_first: # padding加载前面\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:# padding加载后面\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        return torch.tensor(indices_list)\n",
    "    \n",
    "    \n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "    \n",
    "\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
    "raw_text = [\"hello world\".split(), \"i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ \".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=False)\n",
    "\n",
    "print(\"raw text-------------------\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices---------------\")\n",
    "for index in indices:\n",
    "    print(index)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:45:07.249166Z",
     "start_time": "2025-01-24T06:45:07.246093Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.795944Z",
     "iopub.status.busy": "2025-01-25T07:55:08.795755Z",
     "iopub.status.idle": "2025-01-25T07:55:08.798697Z",
     "shell.execute_reply": "2025-01-25T07:55:08.798333Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.795929Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'sum@@'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "idx2word[2230]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:46:29.054028Z",
     "start_time": "2025-01-24T06:46:29.051008Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.799417Z",
     "iopub.status.busy": "2025-01-25T07:55:08.799119Z",
     "iopub.status.idle": "2025-01-25T07:55:08.801915Z",
     "shell.execute_reply": "2025-01-25T07:55:08.801563Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.799402Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "decode text\n",
      "[BOS] hello world [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n",
      "[BOS] i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ [EOS]\n",
      "[BOS] this is a test [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n"
     ]
    }
   ],
   "source": [
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:47:44.738465Z",
     "start_time": "2025-01-24T06:47:44.735674Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.802659Z",
     "iopub.status.busy": "2025-01-25T07:55:08.802342Z",
     "iopub.status.idle": "2025-01-25T07:55:08.805208Z",
     "shell.execute_reply": "2025-01-25T07:55:08.804851Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.802644Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i really liked summerslam due look arena , cur\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 输入字符串\n",
    "text = \"i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ \"\n",
    "\n",
    "# 使用正则表达式替换 \"@@ \" 为空字符串\n",
    "cleaned_text = re.sub(r'@@\\s*', '', text)\n",
    "\n",
    "print(cleaned_text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T06:51:25.299316Z",
     "start_time": "2025-01-24T06:51:25.295189Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.805890Z",
     "iopub.status.busy": "2025-01-25T07:55:08.805641Z",
     "iopub.status.idle": "2025-01-25T07:55:08.809352Z",
     "shell.execute_reply": "2025-01-25T07:55:08.808989Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.805876Z"
    }
   },
   "outputs": [],
   "source": [
    "def collate_fct(batch):\n",
    "    \"\"\"\n",
    "    把字符串列表转化为tensor\n",
    "    :param batch:\n",
    "    :return:\n",
    "    \"\"\"\n",
    "    text_list = [item[0] for item in batch] #batch中每个item的第一个元素是text,是输入，类型为list\n",
    "    label_list = [item[1] for item in batch] #batch中每个item的第二个元素是label,是输出，类型为int\n",
    "    # 这里使用 padding first\n",
    "    text_list = tokenizer.encode(text_list, padding_first=True).to(dtype=torch.int)\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "batch_size = 128\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-30T07:00:33.794767500Z",
     "start_time": "2024-07-30T07:00:33.778195400Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.810107Z",
     "iopub.status.busy": "2025-01-25T07:55:08.809862Z",
     "iopub.status.idle": "2025-01-25T07:55:08.820540Z",
     "shell.execute_reply": "2025-01-25T07:55:08.820146Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.810092Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 128560\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "================================== 一层双向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 128560\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "       lstm.weight_ih_l0_reverse        paramerters num: 4096\n",
      "       lstm.weight_hh_l0_reverse        paramerters num: 16384\n",
      "        lstm.bias_ih_l0_reverse         paramerters num: 256\n",
      "        lstm.bias_hh_l0_reverse         paramerters num: 256\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "================================== 两层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 128560\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "           lstm.weight_ih_l1            paramerters num: 16384\n",
      "           lstm.weight_hh_l1            paramerters num: 16384\n",
      "            lstm.bias_ih_l1             paramerters num: 256\n",
      "            lstm.bias_hh_l1             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "class LSTM(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.embeding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True, bidirectional=bidirectional)\n",
    "        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)\n",
    "        self.fc = nn.Linear(hidden_dim, 1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # [bs, seq length]\n",
    "        x = self.embeding(x)\n",
    "        # [bs, seq length, embedding_dim] -> shape [bs, seq length, hidden_dim ]\n",
    "        seq_output, (hidden, cell) = self.lstm(x)\n",
    "\n",
    "        x = seq_output[:, -1, :]\n",
    "        # 取最后一个时间步的输出 (这也是为什么要设置padding_first=True的原因)\n",
    "        x = self.layer(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "    \n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 128))\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层单向 LSTM \"))       \n",
    "for key, value in LSTM().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层双向 LSTM \"))       \n",
    "for key, value in LSTM(bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 两层单向 LSTM \"))       \n",
    "for key, value in LSTM(num_layers=2).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.821321Z",
     "iopub.status.busy": "2025-01-25T07:55:08.820992Z",
     "iopub.status.idle": "2025-01-25T07:55:08.843916Z",
     "shell.execute_reply": "2025-01-25T07:55:08.843530Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.821306Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        # 二分类\n",
    "        preds = logits > 0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:08.844812Z",
     "iopub.status.busy": "2025-01-25T07:55:08.844389Z",
     "iopub.status.idle": "2025-01-25T07:55:10.404922Z",
     "shell.execute_reply": "2025-01-25T07:55:10.404447Z",
     "shell.execute_reply.started": "2025-01-25T07:55:08.844796Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-01-25 15:55:09.046638: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n",
      "2025-01-25 15:55:09.056835: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "E0000 00:00:1737791709.069107     950 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "E0000 00:00:1737791709.072807     950 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
      "2025-01-25 15:55:09.085278: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
      "To enable the following instructions: AVX2 AVX512F AVX512_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n"
     ]
    }
   ],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:10.408472Z",
     "iopub.status.busy": "2025-01-25T07:55:10.407927Z",
     "iopub.status.idle": "2025-01-25T07:55:10.412743Z",
     "shell.execute_reply": "2025-01-25T07:55:10.412231Z",
     "shell.execute_reply.started": "2025-01-25T07:55:10.408454Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:10.413878Z",
     "iopub.status.busy": "2025-01-25T07:55:10.413452Z",
     "iopub.status.idle": "2025-01-25T07:55:10.417914Z",
     "shell.execute_reply": "2025-01-25T07:55:10.417355Z",
     "shell.execute_reply.started": "2025-01-25T07:55:10.413850Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:55:10.419003Z",
     "iopub.status.busy": "2025-01-25T07:55:10.418602Z",
     "iopub.status.idle": "2025-01-25T07:57:04.939613Z",
     "shell.execute_reply": "2025-01-25T07:57:04.939167Z",
     "shell.execute_reply.started": "2025-01-25T07:55:10.418976Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 3920/3920 [01:53<00:00, 34.45it/s, epoch=19]\n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits > 0\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = LSTM()\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 (但是二分类)\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/imdb-lstm-subword\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/imdb-lstm-subword\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    test_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:57:04.940560Z",
     "iopub.status.busy": "2025-01-25T07:57:04.940176Z",
     "iopub.status.idle": "2025-01-25T07:57:05.111747Z",
     "shell.execute_reply": "2025-01-25T07:57:05.111321Z",
     "shell.execute_reply.started": "2025-01-25T07:57:04.940534Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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nwaiX79+zJkzR7Ns/vz59OvXr5xGVHkI5/NRt27dMhiRQCAQlIywxNDJkyfxeDyGudapqalF7r9q1So2b97MjBkzgm4XTm52KKTlwvd7zezLnE+z+LB3F+gQubCRoTLPo74mQpZl8lxlL4pyT53FYTOHnB5z33338ffff/P333/z1ltvAUoN5P3338+3337LSy+9xNatW5k1axYNGzbkySefZM2aNeTk5NCmTRsmTJjAwIEDfcfr0qUL9957L/feey8AiYmJvPnmm8ybN4+FCxdSv359XnjhBVJSUoocmzf/OTMz03eH+5dffmHixIns2bOH5ORk7rrrLsaOHevb56OPPuK9997j8OHDJCQk0K9fPz755BMAfv75Z1599VX27t1LdHQ0Xbp04YsvvjC8EZWdnR2wNqI8muqGS1ZWFrt27fI937t3Lxs2bKBWrVo0adKE8ePHc/jwYT799FMA7rnnHt5++20effRRbr/9dhYuXMi3335bqnWssiyT6/L4nkuSRG6+B2u+u9QjQ9E2S0ifkVGjRvk+H2+++SYA//d//8fo0aOZM2cOTz31FJs2bWLevHk0btyYcePGsWLFCrKzs2nfvj0TJ07UGFPo00hNJhMffvghs2fPZu7cuTRs2JDJkydz2WWXFTk2j8fDXXfdxcKFCzl27BhNmjThvvvu44EHHtBsN3PmTCZPnsyuXbuoVasWV199NW+//TYAZ8+e5bHHHuOnn34iPT2dVq1a8corr3DppZeGOpUCAQBr95/mzQW7mHBpB1olxZX3cAQlpEzd5GbMmEHnzp0Dmi14CSc3u0hyzzD//f/RNrMBb2w+l50vDNWs/mfXSY6l53Ftz0bhHbcaInJhI0NVmEd9TUROvpvur5aPuNv87BBi7KF9lb3zzjvs27ePjh07+m64bNmyBYAXX3yR1157jRYtWpCYmMjBgwcZMWIEr7zyClFRUXz22WfccMMNbNu2jSZNmgBKZNzhcGi+lyZNmsQrr7zClClTePvtt7n77rvZu3evX8qwHu+Nnvj4eBISEli7di2jR4/mmWee4brrrmPZsmWMHTuWBg0aMGrUKNasWcPjjz/OJ598Qv/+/Tl9+jRLliwhISGBo0ePcuedd/Lqq69yxRVXkJmZyZIlS4iPjycurvCH21tvERsbG7A2IpJ52aXFmjVruPDCC33Pvb8ft912Gx9//DFHjx7lwIEDvvXNmzdn9uzZPPzww7z55ps0atSIjz76KKK22npyXR46TJhbascPxtbnh4X0GXnzzTfZsWMHnTp14vnnnwcKPx+PP/44r7/+uubzkZKSwksvvURUVBSffvopI0aMYPv27b7PhxHPPfccr732GpMmTWLatGncdNNN7N+/v8jPhyRJNGrUiO+++47atWuzbNky7rrrLpKTk7n44osBeO+99xg3bhyvvPIKw4cPJz09naVLl/r2Hz58OJmZmXz++ee0bNmSrVu3VnmXOEHpcPV7SjbU3Z+tYcF/B5bvYAQlJiwxVKdOHSwWi2Gudb169YLum52dzddff+37gg1GOLnZRbL6G1Kyf6KbrRZznb35Z/dp+reswzerD3Jh2yRu/2QdAH1a1KFVkggbhYLIhY0MlXke9TUR5VnzEM75ExMTsdvtxMbG0qBBAwB27NgBwPPPP6+5GK5Tpw7du3f3PX/xxRf56aef+O233zTRGX2twqhRo7jpppsAJco9bdo01qxZ47tgC/Y61K9n6tSpDBo0iAkTJgDQrl07UlNTmTx5MrfffjuHDh0iNjaWyy67jPj4eJo3b07Pnj0B5TvZ7XZz9dVX07RpUwC6du3qd051vUWg2ojK8B4dOHCgL+XPiI8//thwn/Xr15fiqCofNWrUwG63ExMT4/tN92Z9PP/88wwZMsS3ba1atTTvqRdeeIEff/yRX375RfP50DNq1ChuuOEGAF5++WXeeustVq1aVeTnw2azaTJGmjdvzvLly/nuu+98+7744ov897//1Rg29O7dG4A///yTVatWsW3bNtq0aQMoBg8CQUk4dCa3vIcgiABhiSG73U7Pnj1ZsGABV1xxBaD8mC5YsCDolx/Ad999h9Pp5Oabby72YIuD1OtOjs2dSgPTSW63/M7tH0dxVfeGzFp/mFfthal92U5PkKMIBIJgRNssbH2+9O6q65EkicyMTOIT4om2RebObq9evTTPs7KyePbZZ5k9ezZHjx7F7XaTm5uriTAY0aVLF9/j2NhYEhISOHHiRNjj2bZtG5dffrlm2YABA5g6dSoej4chQ4bQtGlTWrRowcUXX8zFF1/MlVdeSUxMDF27dmXQoEF07tyZYcOGMXToUK655hoSExPDHocgMug/I+r3cFmkyZWUivD5eOedd5g5cyYHDhwgNzeX/Px8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",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-25T07:57:05.112574Z",
     "iopub.status.busy": "2025-01-25T07:57:05.112248Z",
     "iopub.status.idle": "2025-01-25T07:57:07.847464Z",
     "shell.execute_reply": "2025-01-25T07:57:07.847024Z",
     "shell.execute_reply.started": "2025-01-25T07:57:05.112548Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_950/1251314024.py:4: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  model.load_state_dict(torch.load(\"checkpoints/imdb-lstm-subword/best.ckpt\", map_location=\"cpu\"))\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.3739\n",
      "accuracy: 0.8654\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/imdb-lstm-subword/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
